package cn.yilongquan.controller;


import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.yilongquan.TbCourse;
import cn.yilongquan.authorize.PreAuthorize;
import cn.yilongquan.service.TbCourseService;
import cn.yilongquan.util.R;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/course")
public class TbCourseController {

    @Resource
    private TbCourseService courseService;

    // 获取所有课程
    @GetMapping("/all")
    public List<TbCourse> getAllCourses() {
        return courseService.getAllCourses();
    }

    // 分页获取课程
    @GetMapping("/page")
    public ResponseEntity<Map<String, Object>> getCoursesByPage(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {

        List<TbCourse> courses = courseService.getCoursesByPage(page, size);
        int total = courseService.getTotalCount();

        Map<String, Object> result = new HashMap<>();
        result.put("courses", courses);
        result.put("total", total);
        result.put("page", page);
        result.put("size", size);

        return ResponseEntity.ok(result);
    }

    // 删除课程
    @DeleteMapping("/{id}")
    public boolean deleteCourse(@PathVariable Long id) {
        return courseService.deleteCourseById(id);
    }

    // 添加课程
    @PostMapping("/add")
    public boolean addCourse(@RequestBody TbCourse course) {
        return courseService.addCourse(course);
    }

    // 更新课程
    @PutMapping("/update")
    public boolean updateCourse(@RequestBody TbCourse course) {
        return courseService.updateCourse(course);
    }

    // 获取单个课程
    @GetMapping("/{id}")
    public TbCourse getCourse(@PathVariable Long id) {
        return courseService.getCourseById(id);
    }

    // 按课程内容模糊查询
    @GetMapping("/search")
    public ResponseEntity<List<TbCourse>> searchCoursesByContent(
            @RequestParam("content") String content
    ) {
        List<TbCourse> courses = courseService.getCoursesByContentLike(content);
        return ResponseEntity.ok(courses);
    }

    // 搜索结果总条数接口
    @GetMapping("/search/count")
    public int getSearchTotalCount(@RequestParam("content") String content) {
        return courseService.getTotalCountByContentLike(content);
    }


    // 导出课程接口 - Hutool 实现
    @GetMapping("/export")
    public void exportCourses(HttpServletResponse response) {

        ExcelWriter writer = null;
        try {
            // 1. 获取所有课程数据
            List<TbCourse> courses = courseService.getAllCourses();

            // 2. 通过工具类创建writer，true表示使用xlsx格式
            writer = ExcelUtil.getWriter(true);

            // 3. 自定义标题别名（字段名 -> 中文标题）
            writer.addHeaderAlias("id", "ID");
            writer.addHeaderAlias("lectureTime", "课程日期");
            writer.addHeaderAlias("week", "星期");
            writer.addHeaderAlias("content", "课程内容");
            writer.addHeaderAlias("teacher", "讲师");
            writer.addHeaderAlias("remark", "备注");
            writer.addHeaderAlias("createTime", "创建时间");

            // 4. 一次性写出内容，使用默认样式
            writer.write(courses, true);

            // 5. 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            String fileName = URLEncoder.encode("课程表", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");

            // 6. 将Excel写入响应输出流
            writer.flush(response.getOutputStream(), true);

        } catch (Exception e) {
            e.printStackTrace();
            try {
                response.reset();
                response.setContentType("application/json");
                response.setCharacterEncoding("utf-8");
                response.getWriter().println("{\"error\":\"导出失败：" + e.getMessage() + "\"}");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } finally {
            // 7. 关闭writer
            if (writer != null) {
                writer.close();
            }
        }
    }


    // 导入课程接口 - Hutool 实现
    @PostMapping("/import")
    public R importCourses(@RequestParam("file") MultipartFile file) {
        // 定义返回结果封装类
        Map<String, Object> result = new HashMap<>();
        int total = 0;
        int successCount = 0;
        StringBuilder errorMsg = new StringBuilder();

        try (InputStream inputStream = file.getInputStream()) {
            // 打印前端上传的文件基本信息
            System.out.println("===== 接收到前端上传的文件 =====");
            System.out.println("文件名: " + file.getOriginalFilename());
            System.out.println("文件大小: " + file.getSize() + " 字节");
            System.out.println("文件类型: " + file.getContentType());

            // 1. 通过Hutool的ExcelUtil创建Excel读取器
            ExcelReader reader = ExcelUtil.getReader(inputStream);

            // 关键步骤：绑定 Excel 表头与实体类字段名
            reader.addHeaderAlias("课程日期", "lectureTime");
            reader.addHeaderAlias("星期", "week");
            reader.addHeaderAlias("课程内容", "content");
            reader.addHeaderAlias("讲师", "teacher");
            reader.addHeaderAlias("备注", "remark");

            // 2. 读取Excel数据并转换为TbCourse对象列表
            List<TbCourse> courseList = reader.readAll(TbCourse.class);
            total = courseList.size();

            // 打印解析后的总数据量
            System.out.println("\n===== Excel解析结果 =====");
            System.out.println("共解析出 " + total + " 条课程数据");

            // 3. 遍历处理每条数据
            for (int i = 0; i < courseList.size(); i++) {
                TbCourse course = courseList.get(i);
                int rowNum = i + 2; // Excel行号（表头+1）

                // 打印当前行的原始解析数据
                System.out.println("\n===== 处理第 " + rowNum + " 行数据 =====");
                System.out.println("原始解析数据: " + course.toString()); // 需要TbCourse实现toString()方法

                try {
                    // 4. 数据校验及日志打印
                    System.out.println("开始校验第 " + rowNum + " 行数据...");

                    if (course.getLectureTime() == null) {
                        String msg = "第" + rowNum + "行：课程日期不能为空";
                        errorMsg.append(msg).append("；");
                        System.out.println("校验失败：" + msg);
                        continue;
                    }
                    System.out.println("课程日期校验通过: " + course.getLectureTime());

                    if (course.getWeek() == null || course.getWeek().trim().isEmpty()) {
                        String msg = "第" + rowNum + "行：星期不能为空";
                        errorMsg.append(msg).append("；");
                        System.out.println("校验失败：" + msg);
                        continue;
                    }
                    System.out.println("星期校验通过: " + course.getWeek());

                    if (course.getContent() == null || course.getContent().trim().isEmpty()) {
                        String msg = "第" + rowNum + "行：课程内容不能为空";
                        errorMsg.append(msg).append("；");
                        System.out.println("校验失败：" + msg);
                        continue;
                    }
                    System.out.println("课程内容校验通过: " + course.getContent());

                    if (course.getTeacher() == null || course.getTeacher().trim().isEmpty()) {
                        String msg = "第" + rowNum + "行：讲师不能为空";
                        errorMsg.append(msg).append("；");
                        System.out.println("校验失败：" + msg);
                        continue;
                    }
                    System.out.println("讲师校验通过: " + course.getTeacher());

                    // 5. 设置自动生成的字段
                    // 替换 new Date()
                    course.setCreateTime(LocalDateTime.now());
                    System.out.println("自动填充时间字段: createTime=" + course.getCreateTime());

                    // 6. 调用服务层保存数据
                    boolean saveSuccess = courseService.addCourse(course);
                    if (saveSuccess) {
                        successCount++;
                        System.out.println("第 " + rowNum + " 行数据保存成功");
                    } else {
                        String msg = "第" + rowNum + "行：数据库保存失败";
                        errorMsg.append(msg).append("；");
                        System.out.println("处理失败：" + msg);
                    }
                } catch (Exception e) {
                    String msg = "第" + rowNum + "行：处理失败，" + e.getMessage();
                    errorMsg.append(msg).append("；");
                    System.out.println("异常信息：" + msg);
                    e.printStackTrace(); // 打印异常堆栈
                }
            }

            // 7. 组装返回结果
            result.put("success", successCount > 0 || total == 0);
            result.put("total", total);
            result.put("successCount", successCount);
            if (errorMsg.length() > 0) {
                result.put("message", errorMsg.toString());
            }

            // 打印最终导入统计
            System.out.println("\n===== 导入完成 =====");
            System.out.println("总条数: " + total + ", 成功条数: " + successCount);
            if (errorMsg.length() > 0) {
                System.out.println("错误信息: " + errorMsg.toString());
            }

            return R.ok(result);

        } catch (Exception e) {
            String errMsg = "导入失败：" + e.getMessage();
            System.out.println("\n===== 导入发生异常 =====");
            System.out.println(errMsg);
            e.printStackTrace();
            return R.fail(errMsg);
        }
    }


    @ApiOperation(value = "批量删除课程表信息")
    @PostMapping("/deleteAll")
    @PreAuthorize(sn = "article:batchDelete", name = "批量删除课程表", descs = "根据ID列表批量删除课程表")
    public R batchDelete(@RequestBody Long[] ids){
        courseService.batchDelete(ids);
        return R.ok();
    }
}